﻿using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common.Tool.FileTools
{
    public class ZipHelper
    {
        /// <summary>    
        /// 获取所有文件    
        /// </summary>    
        /// <returns></returns>    
        private Dictionary<string, DateTime> GetAllFies(string dir)
        {
            Dictionary<string, DateTime> FilesList = new Dictionary<string, DateTime>();
            DirectoryInfo fileDire = new DirectoryInfo(dir);
            if (!fileDire.Exists)
            {
                throw new System.IO.FileNotFoundException("目录:" + fileDire.FullName + "没有找到!");
            }
            GetAllDirFiles(fileDire, FilesList);
            GetAllDirsFiles(fileDire.GetDirectories(), FilesList);
            return FilesList;
        }
        /// <summary>    
        /// 获取一个文件夹下的所有文件夹里的文件    
        /// </summary>    
        /// <param name="dirs"></param>    
        /// <param name="filesList"></param>    
        private void GetAllDirsFiles(DirectoryInfo[] dirs, Dictionary<string, DateTime> filesList)
        {
            foreach (DirectoryInfo dir in dirs)
            {
                foreach (FileInfo file in dir.GetFiles("*.*"))
                {
                    filesList.Add(file.FullName, file.LastWriteTime);
                }
                GetAllDirsFiles(dir.GetDirectories(), filesList);
            }
        }
        /// <summary>    
        /// 获取一个文件夹下的文件    
        /// </summary>    
        /// <param name="dir">目录名称</param>    
        /// <param name="filesList">文件列表HastTable</param>    
        private void GetAllDirFiles(DirectoryInfo dir, Dictionary<string, DateTime> filesList)
        {
            foreach (FileInfo file in dir.GetFiles("*.*"))
            {
                filesList.Add(file.FullName, file.LastWriteTime);
            }
        }
        /// <summary>    
        /// 压缩文件夹    
        /// </summary>    
        /// <param name="dirPath">要打包的文件夹</param>    
        /// <param name="fileName">目标文件名</param>    
        /// <param name="CompressionLevel">压缩品质级别（0~9）</param>    
        /// <param name="deleteDir">是否删除原文件夹</param>  
        public string CompressDirectory(string dirPath, string fileName, int CompressionLevel, bool deleteDir)
        {
            string GzipFilePath = dirPath.Substring(0, dirPath.LastIndexOf("\\")) + "\\" + fileName + ".zip";
            using (ZipOutputStream zipoutputstream = new ZipOutputStream(File.Create(GzipFilePath)))
            {
                zipoutputstream.SetLevel(CompressionLevel);
                Crc32 crc = new Crc32();
                Dictionary<string, DateTime> fileList = GetAllFies(dirPath);
                foreach (var file in fileList)
                {
                    try
                    {
                        FileStream fs = File.OpenRead(file.Key);
                        byte[] buffer = new byte[fs.Length];
                        fs.Read(buffer, 0, buffer.Length);
                        ZipEntry entry;
                        entry = new ZipEntry("\\" + fileName + file.Key.Substring(dirPath.Length));
                        entry.DateTime = file.Value;
                        entry.Size = fs.Length;
                        fs.Close();
                        crc.Reset();
                        crc.Update(buffer);
                        entry.Crc = crc.Value;
                        zipoutputstream.PutNextEntry(entry);
                        zipoutputstream.Write(buffer, 0, buffer.Length);
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                }
            }
            if (deleteDir)
            {
                Directory.Delete(dirPath, true);
            }
            return GzipFilePath;
        }
        /// <summary>    
        /// 压缩文件夹    
        /// </summary>    
        /// <param name="fileName">目标文件名</param>    
        /// <param name="files">文件内容</param>    
        /// <param name="CompressionLevel">压缩品质级别（0~9）</param>    
        public void CompressDirectory(string fileName, Dictionary<string, byte[]> files, int CompressionLevel)
        {
            using (ZipOutputStream zipoutputstream = new ZipOutputStream(File.Create(fileName)))
            {
                zipoutputstream.SetLevel(CompressionLevel);
                Crc32 crc = new Crc32();
                foreach (var file in files)
                {
                    try
                    {
                        ZipEntry entry;
                        entry = new ZipEntry("\\"  + file.Key);
                        entry.DateTime = DateTime.Now;
                        entry.Size = file.Value.Length;
                        crc.Reset();
                        crc.Update(file.Value);
                        entry.Crc = crc.Value;
                        zipoutputstream.PutNextEntry(entry);
                        zipoutputstream.Write(file.Value, 0, file.Value.Length);
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                }
            }
        }
        #region 解压缩文件
        /// <summary>    
        /// 解压缩文件    
        /// </summary>    
        /// <param name="GzipFile">压缩包文件名</param>    
        /// <param name="targetPath">解压缩目标路径</param>           
        public static void Decompress(string GzipFile, string targetPath)
        {
            try
            {
                string directoryName = targetPath;
                if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);//生成解压目录    
                string CurrentDirectory = directoryName;
                byte[] data = new byte[2048];
                int size = 2048;
                ZipEntry theEntry = null;
                using (ZipInputStream s = new ZipInputStream(File.OpenRead(GzipFile)))
                {
                    while ((theEntry = s.GetNextEntry()) != null)
                    {
                        if (theEntry.IsDirectory)
                        {// 该结点是目录    
                            if (!Directory.Exists(CurrentDirectory + theEntry.Name)) Directory.CreateDirectory(CurrentDirectory + theEntry.Name);
                        }
                        else
                        {
                            if (theEntry.Name != String.Empty)
                            {
                                //  检查多级目录是否存在  
                                if (theEntry.Name.Contains("/"))
                                {
                                    string parentDirPath = theEntry.Name.Remove(theEntry.Name.LastIndexOf("/") + 1);
                                    if (!Directory.Exists(parentDirPath))
                                    {
                                        Directory.CreateDirectory(CurrentDirectory + "\\" + parentDirPath);
                                    }
                                }

                                //解压文件到指定的目录    
                                using (FileStream streamWriter = File.Create(CurrentDirectory + "\\" + theEntry.Name))
                                {
                                    while (true)
                                    {
                                        size = s.Read(data, 0, data.Length);
                                        if (size <= 0) break;
                                        streamWriter.Write(data, 0, size);
                                    }
                                    streamWriter.Close();
                                }
                            }
                        }
                    }
                    s.Close();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
        /// <summary>    
        /// 解压缩文件    
        /// </summary>    
        /// <param name="GzipFile">压缩包文件名</param>    
        /// <param name="targetPath">解压缩目标路径</param>           
        public Dictionary<string, byte[]> Decompress(string GzipFile)
        {
            try
            {
                Dictionary<string, byte[]> files= new Dictionary<string, byte[]>();
                ZipEntry theEntry = null;
                using (ZipInputStream s = new ZipInputStream(File.OpenRead(GzipFile)))
                {
                    while ((theEntry = s.GetNextEntry()) != null)
                    {
                        if (theEntry.Name != String.Empty)
                        {
                            List<byte> bytes = new List<byte>();
                            while (true)
                            {
                                byte[] data = new byte[2048];
                                int size = 2048;
                                size = s.Read(data, 0, data.Length);
                                if (size <= 0) break;
                                bytes.AddRange(data);
                            }
                            files.Add(theEntry.Name, bytes.ToArray());
                        }
                    }
                    s.Close();
                }
                return files;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
        #endregion
    }
}
